class LazyChain {
    constructor(obj) {
        const isLZ = (obj instanceof LazyChain);

        this.calls = isLZ ? obj.calls : [];
        this.target = isLZ ? obj.target : obj;
    }

    invoke(methodName, ...args) {
        this.calls.push((target) => {
            const meth = target[methodName];
            return meth.apply(target, args);
        });

        return this;
    }

    force() {
        return this.calls.reduce((pre, cur) => {
            return cur(pre);
        }, this.target);
    }

    tap(fn) {
        this.calls.push((target) => {
            fn(target);
            return target;
        });

        return this;
    }
}

function pipeline(target, ...fns) {
    return fns.reduce((pre, cur) => {
        return cur(pre);
    }, target);
}

function fifth(a) {
    return pipeline(a, n => n + 1, n => n + 1);
}

function negativeFifth(a) {
    return pipeline(a, fifth, n => -n);
}